package com.five.zhh.fiveinfive.room;

import cn.hutool.core.lang.Assert;
import com.five.zhh.fiveinfive.exception.OperateException;
import com.five.zhh.fiveinfive.room.connection.UserRoomConnection;
import com.five.zhh.fiveinfive.room.entity.pojo.Chess;
import com.five.zhh.fiveinfive.room.entity.vo.GameRoomDetailVo;
import com.five.zhh.fiveinfive.room.entity.vo.GameRoomOverviewVo;
import com.five.zhh.fiveinfive.room.user.UserInfoInRoom;
import com.five.zhh.fiveinfive.room.util.ChessUtil;
import lombok.Data;
import lombok.Getter;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Data
public class GameRoomManager {

    @Getter
    private static Map<String, GameRoom> gameRooms = new ConcurrentHashMap<>();

    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    public static GameRoom createGameRoom(int size) {
        int CODE_LENGTH = 4;
        StringBuilder code = new StringBuilder(4);
        Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < CODE_LENGTH; i++) {
            int index = random.nextInt(CHARACTERS.length());
            code.append(CHARACTERS.charAt(index));
        }
        if (size < 0) {
            size = ChessUtil.BOARD_SIZE;
        }
        return new GameRoom(size, code.toString(), new Chess[size][size]);
    }

    public static GameRoom getGameRoom(String roomCode) {
        return gameRooms.get(roomCode);
    }

    public static void addGameRoom(GameRoom gameRoom) {
        if (gameRooms.containsKey(gameRoom.getRoomCode())) {
            throw new OperateException("该房间已存在");
        }
        gameRooms.put(gameRoom.getRoomCode(), gameRoom);
    }

    public static boolean joinRoom(String roomCode, UserRoomConnection userRoomConnection) {
        GameRoom gameRoom = gameRooms.get(roomCode);
        if (null == gameRoom) throw new OperateException("房间不存在");
        boolean successJoin = gameRoom.addPlayer(userRoomConnection);
        if (!successJoin) {
            successJoin = gameRoom.addSpectator(userRoomConnection);
        }
        if (!successJoin) {
            throw new OperateException("房间已满");
        }
        return successJoin;
    }

    public static GameRoom createGameRoom() {
        GameRoom room = createGameRoom(ChessUtil.BOARD_SIZE);
        addGameRoom(room);
        return room;
    }

    public static List<GameRoomOverviewVo> getRoomOverview() {
        List<GameRoomOverviewVo> result = new ArrayList<>(gameRooms.size());
        gameRooms.forEach(((roomCode, gameRoom) -> {
            GameRoomOverviewVo vo = new GameRoomOverviewVo();
            vo.setRoomCode(roomCode);
            vo.setPlayers(gameRoom.getPlayers().values().stream().map(UserRoomConnection::getUserInfo).toList());
            vo.setSpectators(gameRoom.getSpectators().values().stream().map(UserRoomConnection::getUserInfo).toList());
            if (gameRoom.getBlackUser() != null) {
                vo.setBlack(gameRoom.getBlackUser().getUserInfo());
            }
            if (gameRoom.getWhiteUser() != null) {
                vo.setWhite(gameRoom.getWhiteUser().getUserInfo());
            }
            vo.setRunning(gameRoom.getRunning().get());
            result.add(vo);
        }));
        return result;
    }

    public static GameRoom createTestGameRoom() {
        GameRoom testRoom = createGameRoom();
        testRoom.setRoomCode("1234");
        addGameRoom(testRoom);
        return testRoom;
    }

    public static int clearGameRoom() {
        Map<String, GameRoom> rooms = gameRooms;
        int count = rooms.size();
        Iterator<Map.Entry<String, GameRoom>> iterator = rooms.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, GameRoom> entry = iterator.next();
            GameRoom room = entry.getValue();
            iterator.remove();
        }
        return count;
    }

    public static void removeGameRoom(String roomCode) {
        GameRoom gameRoom = gameRooms.get(roomCode);
        if (gameRoom != null) {
            gameRooms.remove(roomCode);
        }
    }

    public static GameRoomDetailVo getGameRoomDetail(String roomCode) {
        GameRoom gameRoom = gameRooms.get(roomCode);
        Assert.notNull(gameRoom, "房间号不正确");
        GameRoomDetailVo vo = new GameRoomDetailVo();
        vo.setRoomCode(gameRoom.getRoomCode());
        vo.setRunningStats(gameRoom.getRunning().get());
        if (gameRoom.getBlackUser() != null) {
            vo.setBlackUser(new UserInfoInRoom(gameRoom.getBlackUser().getUserInfo(), gameRoom.getUserRoleInRoom(gameRoom.getBlackUser().getUserInfo()), gameRoom.getFirstStep().get() ? true : false));
        }
        if (gameRoom.getWhiteUser() != null) {
            vo.setWhiteUser(new UserInfoInRoom(gameRoom.getWhiteUser().getUserInfo(), gameRoom.getUserRoleInRoom(gameRoom.getWhiteUser().getUserInfo()), gameRoom.getFirstStep().get() ? false : true));
        }
        vo.setBlackScore(gameRoom.getBlackScore().get());
        vo.setWhiteScore(gameRoom.getWhiteScore().get());
        vo.setFirstStep(gameRoom.getFirstStep());
        vo.setCreateTimestamp(gameRoom.getCreateTimestamp());
        Chess[][] chessboard = gameRoom.getChessboard();
        int[][] chess = new int[gameRoom.getBoardSize()][gameRoom.getBoardSize()];
        vo.setChessboard(chess);
        for (int i = 0; i < chessboard.length; i++) {
            for (int j = 0; j < chessboard.length; j++) {
                chess[i][j] = chessboard[i][j] == null ? 0 : chessboard[i][j].getColor();
            }
        }
        return vo;
    }
}
